import tkinter as tk  
from tkinter import simpledialog, Label, Toplevel, messagebox, Menu
from flask import Flask, render_template
import efinance as ef
import json   
from datetime import datetime    
from tkinter import Scrollbar, Canvas
import plot 
import pandas as pd
import qstock as qs
from tkinter import ttk, Scrollbar

# Global variables
STOCK_CODES_FILE = 'stock_codes.json' 
stock_codes = []
stock_data = {}  # Dictionary to store stock data including cost and reorder quantity
language = "ZH"  # Default language is English


# The download_historical_data function to download historical stock data
def download_historical_data(stock_code, start_date, end_date):
    try:
        # Use efinance to get historical stock data
        historical_data = ef.stock.get_quote_history(stock_code, start=start_date, end=end_date)

        if not historical_data.empty:
            # Save the historical data to a CSV file
            file_name = f"{stock_code}_historical_data.csv"
            historical_data.to_csv(file_name, index=False)
            messagebox.showinfo("Success", f"Historical data downloaded and saved to {file_name}")
        else:
            messagebox.showinfo("Info", "No historical data found for the specified stock code and date range.")

    except Exception as e:
        messagebox.showerror("Error", str(e))


def save_data():
    """Save stock codes and related data to a file"""
    data = {'codes': stock_codes, 'stock_data': stock_data}
    with open(STOCK_CODES_FILE, "w") as file:  
        json.dump(data, file)  
    messagebox.showinfo("Success", "Stock data saved")

def load_data():
    """Load stock codes and related data from a file"""
    try:
        with open(STOCK_CODES_FILE, "r") as file:  
            data = json.load(file)
            global stock_codes, stock_data
            stock_codes = data['codes']
            stock_data = data['stock_data']
            show_stock_codes()
            #messagebox.showinfo("Success", "Stock data loaded")
    except FileNotFoundError:  
        messagebox.showinfo("Info", "No stock data found.")
    except json.JSONDecodeError:  
        messagebox.showerror("Error", "Error loading stock data.")

def update_clock():  
    """Update clock label with current time"""
    current_time = datetime.now().strftime("%H:%M:%S %p")  
    clock_label.config(text=current_time)  
    clock_label.after(1000, update_clock)  # Update time every second

def update_result_label(text):  
    """Update result label with given text"""
    result_label.config(text=text)

def update_stock_info():  
    """Update stock information display"""
    try:  
        # Use efinance to get latest stock information
        df = ef.stock.get_latest_quote(stock_codes)

        if not df.empty:
            # Add cost information to the DataFrame
            
            df['成本'] = [stock_data.get(code, {}).get('cost', '') for code in df['代码']]

            result_text = df[['成本','代码', '名称', '涨跌幅', '最新价','更新时间']].to_string(index=False)  
            update_result_label(result_text)

             # Check for alert thresholds
            for index, row in df.iterrows():
                stock_code = row['代码']
                rate = row['涨跌幅']
                latest_price = row['最新价']
                cost = stock_data.get(stock_code, {}).get('cost', '')
                total_rate = abs(latest_price - cost)/cost if cost is not None else None
                if  abs(total_rate) >= 10:
                    messagebox.showinfo("Alert", f"Rate of change for {stock_code} has exceeded 10%")
                    
    except Exception as e:  
        messagebox.showerror("Error", str(e))  
      
    # Update stock information periodically
    root.after(10000, update_stock_info)  # Update every 10 seconds

def add_stock_code():  
    """Add a stock code to the list"""
    stock_code = simpledialog.askstring("Input", "Enter stock code:")
    if stock_code:  
        stock_codes.append(stock_code)  
        add_cost_reorder(stock_code)  # Add cost and reorder data for the new stock code
        show_stock_codes()
        update_stock_info()  # Update stock information display
        save_data()  # Save data after adding new stock code

def add_cost_reorder(stock_code):
    """Add cost and reorder quantity for a stock code"""
    cost = simpledialog.askfloat("Input", f"Enter cost for {stock_code}:")
    reorder_quantity = simpledialog.askinteger("Input", f"Enter reorder quantity for {stock_code}:")
    if cost is not None and reorder_quantity is not None:
        stock_data[stock_code] = {'cost': cost, 'reorder_quantity': reorder_quantity}
        save_data()
    else:
        messagebox.showerror("Error", "Invalid input for cost or reorder quantity.")

def show_stock_codes():  
    """Show stock codes in the result label"""
    code_list = "\n".join(stock_codes)
    update_result_label(f"Current Stock Codes:\n{code_list}")

def on_closing():  
    """Handle window closing"""
    save_data()  # Save data before closing
    root.destroy()  # Destroy window          
  
# 删除指定的股票代码  
def delete_stock_code():  
    stock_code_to_delete = simpledialog.askstring("删除", "请输入要删除的股票代码：")  
    if stock_code_to_delete and stock_code_to_delete in stock_codes:  
        stock_codes.remove(stock_code_to_delete)  
        show_stock_codes()  
        messagebox.showinfo("成功", f"股票代码 {stock_code_to_delete} 已成功删除。")  
    else:  
        messagebox.showinfo("提示", "未找到要删除的股票代码，请重新输入。")  

def create_toplevel_Futures():  
    if hasattr(root, 'top') and root.top:  
        root.top.destroy()  # 销毁已存在的窗口  
  
    top = Toplevel(root)  
    top.title("期货信息")  
    top.attributes("-alpha", 0.5)  # 设置窗口透明度  
    top.attributes('-topmost', True)  # 确保窗口始终在最上层  
  
    label_frame = tk.Frame(top)  
    label_frame.pack(pady=20, padx=20)  
  
    result_label = tk.Label(label_frame, font=("Helvetica", 16))  
    result_label.pack()  
  
    def update_futures_info():  
        realtime_quotes = ef.futures.get_realtime_quotes()  
        quote_id = '114.c2405'  # 假设您知道要查询的期货行情ID  
        target_quote = realtime_quotes[realtime_quotes['行情ID'] == quote_id]  
  
        if not target_quote.empty:  
            result_text = f"期货名称: {target_quote['期货名称'].values[0]}, 最新价: {target_quote['最新价'].values[0]}, 今开: {target_quote['今开'].values[0]}"  
            result_label.config(text=result_text)  
            print(f"期货 {quote_id} 的实时价格为: {result_text}")  
        else:  
            result_label.config(text="未找到期货行情ID的实时价格信息。")  
            print(f"未找到期货行情ID为 {quote_id} 的实时价格信息。")  
  
    # 定时更新期货信息，这里使用root的after方法模拟定时器  
    def update_periodically():  
        update_futures_info()  
        root.after(10000, update_periodically)  # 每10秒更新一次  
  
    update_periodically()  # 开始定时更新  
    top.lift()             
#------------------------------------------------------------------------------------------------------------------------------

def create_toplevel_window():
    """Create a new Toplevel window to display stock information"""
    if hasattr(root, 'top') and root.top:
        root.top.destroy()  # Destroy the existing window if it exists

    top = Toplevel(root)
    top.title("Stock Information")
    top.attributes("-alpha", 0.5)  # Set window transparency
    top.attributes('-topmost', True)  # Ensure the window is always on top

    root.top = top  # Store the reference to the window in the root object

    # Function to update stock information in the window
    def update_stock_info():
        try:
            # Use efinance to get latest stock information
            df = ef.stock.get_latest_quote(stock_codes)
            if not df.empty:
                for index, row in df.iterrows():
                    stock_code = row['代码']
                    stock_name = row['名称']
                    latest_price = row['最新价']
                    cost = stock_data.get(stock_code, {}).get('cost', '')
                    reorder_quantity = stock_data.get(stock_code, {}).get('reorder_quantity', '')
                    update_time = row['更新时间']
                    rate = row['涨跌幅']
                    # Determine the text color based on the comparison between cost and latest price
                    text_color = "red" if cost < latest_price else "green"
                    text_color2 = "red" if rate > 0 else "green"
                    # Calculate the total cost
                    total_Net = (latest_price - cost)* reorder_quantity if cost is not None and reorder_quantity is not None else None
                    total_Net_formatted = f'{total_Net:.2f}' if total_Net is not None else ''
                    # Create labels to display stock information

                    label_cost = Label(top, text=f"C: {cost}",fg=text_color)
                    label_cost.grid(row=index, column=0, sticky='w')
 
                    label_stock_code = Label(top, text=f"S: {stock_code}")
                    label_stock_code.grid(row=index, column=1, sticky='w')

                    label_stock_name = Label(top, text=f"S: {stock_name}")
                    label_stock_name.grid(row=index, column=2, sticky='w')

                    label_latest_price = Label(top, text=f"LP: {latest_price}")
                    label_latest_price.grid(row=index, column=3, sticky='w')
                    
                    label_total_Net = Label(top, text=f"N: {total_Net_formatted}",fg=text_color)
                    label_total_Net.grid(row=index, column=4, sticky='w')
                    
                    label_rate = Label(top, text=f"R: {rate}",fg=text_color2)
                    label_rate.grid(row=index, column=5, sticky='w')

                    label_reorder_quantity = Label(top, text=f"Qty: {reorder_quantity}")
                    label_reorder_quantity.grid(row=index, column=6, sticky='w')

                    #label_update_time = Label(top, text=f"LU: {update_time}")
                    #label_update_time.grid(row=index, column=7, sticky='w')

            # Calculate and display total net for all items
            total_net_sum = calculate_total_net()
            total_net_sum_formatted = f'Total Net: {total_net_sum:.2f}'

            # Display the total net in the UI (below the stocks)
            label_total_net_sum = Label(top, text=total_net_sum_formatted, fg=text_color)
            label_total_net_sum.grid(row=len(df), column=4, sticky='w')

                    

        except Exception as e:
            messagebox.showerror("Error", str(e))

        # Schedule the next update
        top.after(10000, update_stock_info)

    # Call the update function initially
    update_stock_info()
    top.lift() 

def calculate_total_net():
    total_net_sum = 0
    for stock_code in stock_data:
        cost = stock_data[stock_code].get('cost', 0)  # Default to 0 if not found
        reorder_quantity = stock_data[stock_code].get('reorder_quantity', 0)  # Default to 0 if not found

        try:
            # Assume that ef.stock.get_latest_quote returns a DataFrame with stock info including the latest price
            latest_quote = ef.stock.get_latest_quote(stock_code)

            if latest_quote is not None and not latest_quote.empty:
                latest_price = latest_quote['最新价'].values[0]  # Get the latest price

                # Calculate total net for this stock
                total_net = (latest_price - cost) * reorder_quantity
                total_net_sum += total_net  # Accumulate to the total net sum
        except Exception as e:
            print(f"Error fetching latest quote for {stock_code}: {e}")

    return total_net_sum
      

def trigger_download():
    stock_code = simpledialog.askstring("Input", "Enter stock code:")
    start_date = simpledialog.askstring("Input", "Enter start date (YYYY-MM-DD):")
    end_date = simpledialog.askstring("Input", "Enter end date (YYYY-MM-DD):")
    
    if stock_code and start_date and end_date:
        download_historical_data(stock_code, start_date, end_date)
    else:
        messagebox.showerror("Error", "Invalid input for stock code or date range.")
#----------------------------------------------------------------------------------------------------------
def show_daily_billboard():
    

        try:
            # Use efinance to get the daily billboard information
            daily_billboard = ef.stock.get_daily_billboard()
            selected_columns = ['股票代码', '股票名称','解读', '涨跌幅','收盘价','上榜原因']  # Adjust this to your actual column names
            daily_billboard = daily_billboard[selected_columns]

            # Convert numeric columns to numeric types
            daily_billboard['涨跌幅'] = pd.to_numeric(daily_billboard['涨跌幅'], errors='coerce')

            
            
            if not daily_billboard.empty:
                # Display the daily billboard information
                top = Toplevel(root)
                top.title(f"龙虎榜")
                display_matrix(top, daily_billboard)
            else:
                messagebox.showinfo("Info", f"No daily billboard information found for the stock.")
        except Exception as e:
            messagebox.showerror("Error", str(e))
# Function to display the data with a scrollable area
def display_matrix(window, data):
    tree = ttk.Treeview(window, columns=list(data.columns), show="headings")

    for col in data.columns:
        tree.heading(col, text=col, command=lambda c=col: sort_data(tree, c, False))
        tree.column(col, width=100, anchor="n")

    for index, row in data.iterrows():
        tree.insert("", "end", values=list(row))

    scrollbar = Scrollbar(window, orient="vertical", command=tree.yview)
    scrollbar.pack(side="right", fill="y")
    tree.configure(yscrollcommand=scrollbar.set)

    tree.pack(expand=True, fill="both")

def sort_data(tree, col, reverse):
    # Get all data as a list for sorting
    data = [(tree.set(child, col), child) for child in tree.get_children('')]
    
    # Determine if the column being sorted is numeric or not
    numeric_columns = ['涨跌幅', '收盘价']  # Add more numeric column names as needed
    
    if col in numeric_columns:
        # Convert to float for numeric sorting, pushing non-numeric to the end
        data.sort(key=lambda x: (float(x[0]) if x[0] not in (None, '', 'NaN') else float('inf')), reverse=reverse)
    else:
        # Default string sorting
        data.sort(key=lambda x: x[0] if x[0] else '', reverse=reverse)
    


    # Move the sorted items back to the tree
    for index, (_, child) in enumerate(data):
        tree.move(child, '', index)
    
    # Reset the heading command for the next sort
    tree.heading(col, command=lambda: sort_data(tree, col, not reverse))



def process_news_data_and_plot_wordcloud():
    # Retrieve news data
    start_date = simpledialog.askstring("Input", "Enter start date (YYYYMMDD):")
    end_date = simpledialog.askstring("Input", "Enter end date (YYYYMMDD):")
    
    txt = qs.news_data('cctv', start_date, end_date)
    
    # Handling missing values and converting to string format
    txt_list = ''.join(list(txt.content.apply(lambda s: str(s))))
    
    # Processing text data for word cloud
    word_cloud_data = plot.generate_word_cloud_data(txt_list)
    
    # Plotting word cloud
    plot.plot_wordcloud(word_cloud_data)
#----------------------------------------------------------------------------------------------------------    
def switch_language():
    global language
    if language == "EN":
        language = "ZH"
    else:
        language = "EN"
    update_menu_language()

def update_menu_language():
    global menu_bar, file_menu, edit_menu, language_menu


    
    if language == "EN":
        
    # 删除现有的菜单栏
        menu_bar.delete(0, tk.END)

    # 创建新的菜单栏和菜单
        menu_bar = Menu(root)
        root.config(menu=menu_bar)

# File menu
        file_menu = Menu(menu_bar, tearoff=0)
        menu_bar.add_cascade(label="股票", menu=file_menu)
        file_menu.add_command(label="Add Stock Code", command=add_stock_code)
        file_menu.add_command(label="Save Stock Data", command=save_data) 
        file_menu.add_command(label="Show Stock Data", command=update_stock_info)  
        file_menu.add_command(label="Delete Stock Code", command=delete_stock_code)  
        file_menu.add_separator()
        file_menu.add_command(label="Show plot_wordcloud", command=process_news_data_and_plot_wordcloud)
        file_menu.add_command(label="Show Daily Billboard", command=show_daily_billboard)
        file_menu.add_command(label="Download Historical Data", command=trigger_download)
        file_menu.add_command(label="Exit", command=root.quit)

# Edit menu
        edit_menu = Menu(menu_bar, tearoff=0)
        menu_bar.add_cascade(label="新窗口", menu=edit_menu)
        edit_menu.add_command(label="Show Stock Information", command=create_toplevel_window)
        edit_menu.add_command(label="Show fu Information", command=create_toplevel_Futures)

# Create language menu
        language_menu = Menu(menu_bar, tearoff=0)
        menu_bar.add_cascade(label="语言", menu=language_menu)
        language_menu.add_command(label="Switch to EN" if language == "EN" else "切换到中文", command=switch_language)

        file_menu.entryconfig(0, label="添加股票代码")
        file_menu.entryconfig(1, label="保存股票代码")
        file_menu.entryconfig(2, label="显示股票代码")
        file_menu.entryconfig(3, label="删除股票代码")
        file_menu.entryconfig(5, label="词图")        
        file_menu.entryconfig(6, label="龙虎榜")
        file_menu.entryconfig(7, label="下载历史数据")
        file_menu.entryconfig(8, label="退出")
        edit_menu.entryconfig(0, label="显示股票信息")
        edit_menu.entryconfig(1, label="加载股票代码")
        edit_menu.entryconfig(2, label="显示期货")
        root.title("股票信息查询")
        menu_bar.entryconfig(0, label="股票")
        menu_bar.entryconfig(1, label="新窗口")
        menu_bar.entryconfig(2, label="语言")

    else:
        
    # 删除现有的菜单栏
        menu_bar.delete(0, tk.END)

    # 创建新的菜单栏和菜单
    # Create menu bar
        menu_bar = Menu(root)  
        root.config(menu=menu_bar)  

# File menu
        file_menu = Menu(menu_bar, tearoff=0)  
        menu_bar.add_cascade(label="Stock", menu=file_menu)

        file_menu.add_command(label="Add Stock Code", command=add_stock_code)
        file_menu.add_command(label="Save Stock Data", command=save_data) 
        file_menu.add_command(label="Show Stock Data", command=update_stock_info)  
        file_menu.add_command(label="Delete Stock Code", command=delete_stock_code)  
        file_menu.add_separator()
        file_menu.add_command(label="Show plot_wordcloud", command=process_news_data_and_plot_wordcloud)        
        file_menu.add_command(label="Show Daily Billboard", command=show_daily_billboard)
        file_menu.add_command(label="Download Historical Data", command=trigger_download)
        file_menu.add_command(label="Exit", command=root.quit)

# Edit menu
        edit_menu = Menu(menu_bar, tearoff=0)  
        menu_bar.add_cascade(label="New Window", menu=edit_menu)  
        edit_menu.add_command(label="Show Stock Information", command=create_toplevel_window)
        edit_menu.add_command(label="Show fu Information", command=create_toplevel_Futures)

# Create language menu
        language_menu = Menu(menu_bar, tearoff=0)
        menu_bar.add_cascade(label="Language", menu=language_menu)
        language_menu.add_command(label="Switch to EN" if language == "EN" else "切换到中文", command=switch_language)

        file_menu.entryconfig(0, label="Add Stock Code")
        file_menu.entryconfig(1, label="Save Stock Code")
        file_menu.entryconfig(2, label="Show Stock Code")
        file_menu.entryconfig(3, label="Delete Stock Code")
        file_menu.entryconfig(8, label="Exit")
        file_menu.entryconfig(5, label="Show plot_wordcloud")
        file_menu.entryconfig(6, label="Show Daily Billboard")
        file_menu.entryconfig(7, label="Download Historical Data")
 
        edit_menu.entryconfig(0, label="Show Stock Information")
        edit_menu.entryconfig(1, label="Load Stock Code")
        edit_menu.entryconfig(2, label="Show fu Information")
        root.title("Stock Information Query")
        menu_bar.entryconfig(0, label="Stock")
        menu_bar.entryconfig(1, label="New Window")
        menu_bar.entryconfig(2, label="Language")

# Create switch button
#switch_button = tk.Button(root, text="Switch to ZH", command=switch_language)
#switch_button.pack()

# Update menu language initially
#update_menu_language()
#--------------------------------------------------------------------------------------     


    
# Create main window  
root = tk.Tk()  
root.title("Stock Information")

# Create menu bar
menu_bar = Menu(root)  
root.config(menu=menu_bar)  

# File menu
file_menu = Menu(menu_bar, tearoff=0)  
menu_bar.add_cascade(label="Stock", menu=file_menu)

file_menu.add_command(label="Add Stock Code", command=add_stock_code)
file_menu.add_command(label="Save Stock Data", command=save_data) 
file_menu.add_command(label="Show Stock Data", command=update_stock_info)  
file_menu.add_command(label="Delete Stock Code", command=delete_stock_code)  
file_menu.add_separator()
file_menu.add_command(label="Show plot_wordcloud", command=process_news_data_and_plot_wordcloud)
file_menu.add_command(label="Show Daily Billboard", command=show_daily_billboard)
file_menu.add_command(label="Download Historical Data", command=trigger_download)
file_menu.add_command(label="Exit", command=root.quit)

# Edit menu
edit_menu = Menu(menu_bar, tearoff=0)  
menu_bar.add_cascade(label="New Window", menu=edit_menu)  
edit_menu.add_command(label="Show Stock Information", command=create_toplevel_window)
edit_menu.add_command(label="Show fu Information", command=create_toplevel_Futures)

# Create language menu
language_menu = Menu(menu_bar, tearoff=0)
menu_bar.add_cascade(label="Language", menu=language_menu)
language_menu.add_command(label="Switch to EN" if language == "EN" else "切换到中文", command=switch_language)


# Clock label
clock_label = tk.Label(root, font=('times', 50, 'bold'), bg='green')  
#clock_label.pack()
clock_label.pack(anchor='e')
update_clock()  # Start updating clock


    
# Result label
result_label = Label(root, text="")  
result_label.pack(pady=20)  

load_data()  # Load initial data
#update_stock_info()  # Start updating stock information
root.protocol("WM_DELETE_WINDOW", on_closing)  # Handle window closing

root.mainloop()  # Run main loop
